﻿using System;
using System.Collections.Generic;

namespace EventAggregatorTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("事件聚合器演示程序启动...\n");
            // 创建多个接收者实例，用于接收消息
            var receiver1 = new MessageReceiver("Register接收者1");
            var receiver2 = new MessageReceiver("Register接收者2");
            var receiver3 = new MessageReceiver("Register接收者3");
            Console.WriteLine("Register已创建3个消息接收者并注册到事件聚合器\n"); 
            // 通过事件聚合器发送消息
            Console.WriteLine("Send发送第一条消息...");
            EventAggregator.Instance.Send(new StringMessage("你好，世界！"));
            
            Console.WriteLine("\nSend发送第二条消息...");
            EventAggregator.Instance.Send(new StringMessage("事件聚合器工作正常！"));

            // 测试取消注册功能
            Console.WriteLine("\n取消注册接收者2...");
            EventAggregator.Instance.Unregister<StringMessage>(receiver2);

            Console.WriteLine("\n发送第三条消息（接收者2已取消注册）...");
            EventAggregator.Instance.Send(new StringMessage("再见，世界！"));

            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }

    // record语法糖有属性自动实现的特性，只需声明属性，编译器将自动生成get和init
    // 自动重写了Equals()、==、!=、GetHashCode()、ToString()方法，基于所有属性的值进行比较
    // with表达式支持创建record对象的副本并修改其中的一些属性var modified = original with { Age = 31 };
    // public record Person(string FirstName, string LastName);
    // public class Person
    // {   //init表示只能种在构造函数或者初始化器里设置属性
    //     public string FirstName { get; init}
    //     public string LastName { get; init}
    //     public Person(string firstName, string lastName)
    //     {
    //        FirstName = firstName;
    //        LastName = lastName;
    //     }
    // }
    // 【1】字符串消息类型，包含一个简单的字符串
    public record StringMessage(string Message);
    // 事件聚合器类，负责消息的注册和分发
    public class EventAggregator
    {
        // 【3】使用Lazy<T>实现线程安全的单例模式
        private static readonly Lazy<EventAggregator> _instance = new Lazy<EventAggregator>(() => new EventAggregator());
        public static EventAggregator Instance => _instance.Value;
        // 消息接收者记录类，存储接收者对象和处理方法
        // 这里仅仅是定义了一个类型
        public record MessageReceiver(object Receiver, Action<object> Method);
        // 【4】存储消息类型到接收者列表的映射
        private readonly Dictionary<Type, List<MessageReceiver>> _events = new Dictionary<Type, List<MessageReceiver>>();
        // 私有构造函数确保单例模式，外面无法实例化
        private EventAggregator() { }
        // 【5】注册消息接收者以接收特定类型的消息
        // 存储每种消息类型已经对应的处理方法
        public void Register<TMessage>(object receiver, Action<TMessage> method)
        {
            // 获取消息类型
            var type = typeof(TMessage);
            // 如果类型不存在于字典中，则添加
            if (!_events.ContainsKey(type))
            {
                _events[type] = new List<MessageReceiver>();
            }
            // 添加新的接收者和方法
            // 由于method是个Action<TMessage>类型的委托，与Action<object>不匹配
            // 这里使用在Action<object>(箭头函数)里面调用Action<TMessage>类型的委托
            // 注册的时候先把实际方法传递给Action<TMessage>，再传递到Action<object>内部
            _events[type].Add(new MessageReceiver(receiver, message => method((TMessage)message)));
        }
        // 【6】取消注册消息接收者，使其不再接收特定类型的消息
        public void Unregister<TMessage>(object receiver)
        {
            var type = typeof(TMessage); 
            if (!_events.ContainsKey(type)) return;
            // 查找并移除匹配接收者的所有注册项
            _events[type].RemoveAll(rec => rec.Receiver == receiver);
            // 如果列表为空，则从字典中移除该类型
            if (_events[type].Count == 0)
            {
                _events.Remove(type);
            }
        }
        // 【7】发送消息到所有已注册的接收者
        // 调用Dic里面根据消息类型存储的消息处理方法
        public void Send<TMessage>(TMessage message)
        {
            var type = typeof(TMessage);
            // 如果没有接收者注册此类型的消息，则直接返回
            if (!_events.ContainsKey(type)) return;
            // 遍历所有注册的接收者，调用其处理方法
            // 可能存储了不止一个消息处理方法
            foreach (var rec in _events[type])
            {
                rec.Method.Invoke(message);
            }
        }

    }
    // 消息接收者类，用于接收和处理消息
    public class MessageReceiver
    {
        private readonly string _name;
        // 创建一个新的消息接收者并注册到事件聚合器
        public MessageReceiver(string name = "未命名")
        {
            _name = name;
            // 【2】注册自己到事件聚合器，以接收StringMessage类型的消息
            EventAggregator.Instance.Register<StringMessage>(this, Receive);
        }
        // 【3】处理接收到的StringMessage类型的字符串消息
        public void Receive(StringMessage message)
        {
            // 打印消息内容
            Console.WriteLine($"[{_name}] 收到消息: {message.Message}");
        }
    }
}
